package com.thinkjoy.service;

import com.thinkjoy.util.ConsoleHandle;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;

import java.io.File;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Created by shaojun on 8.21 021.
 */
public class DeployImplement extends DeployAbstract {

    /**
     * 输入部署文件夹的名称
     */
    @Override
    public void inputDeploySourceName() throws IOException {
        logger.info("\n################### 请输入[部署]文件夹绝对路径：###################");

        String inputString = null;
        while (!validPath(inputString)) {
            inputString = ConsoleHandle.inputDirectoryPath();
            logger.info("您的输入为:" + inputString);
        }
        deployEntity.setDeploySource(new File(inputString));
    }

    private boolean validPath(String path) {
        if (StringUtils.isBlank(path)) {
            return false;
        }

        // 判断部署目录与目标路径不能相同
        if (deployEntity.getDeployTarget() != null
                && deployEntity.getDeployTarget().getAbsolutePath().equalsIgnoreCase(new File(path).getAbsolutePath())) {
            logger.error("目标路径与部署文件路径不能一样！\n请重新输入 ：");
            return false;
        }
        return true;
    }

    /**
     * 读取部署文件
     *
     * @param deploySource
     * @return
     */
    @Override
    public Map<String, File> readDeployFiles(File deploySource) {
        Map<String, File> result = new LinkedHashMap<String, File>();
        if (deploySource != null && deploySource.exists() && deploySource.isDirectory()) {
            loadFileMap(deploySource, result);
        }
        return result;
    }

    /**
     * 递归读取部署文件
     *
     * @param dir
     * @param result
     */
    private void loadFileMap(File dir, Map<String, File> result) {
        if (dir.isDirectory()) {
            File[] childFiles = dir.listFiles();
            for (File child : childFiles) {
                String relativePath = child.getAbsolutePath().replace(deployEntity.getDeploySource().getAbsolutePath(), "");
                result.put(relativePath, child);

                if (child.isFile()) {
                    // 文件：计数
                    deployEntity.setDeployCount(deployEntity.getDeployCount() + 1);
                    logger.info("读取成功！总数“" + deployEntity.getDeployCount() + "” ： " + relativePath);
                } else if (child.isDirectory()) {
                    // 文件夹：递归读取
                    loadFileMap(child, result);
                }
            }
        }
    }

    /**
     * 备份目标文件
     *
     * @param deloyDataMap
     */
    @Override
    public void backupTarget(Map<String, File> deloyDataMap) throws IOException {
        logger.info("备份文件路径为：【" + new File(deployEntity.getBackupDir()).getAbsolutePath() + "】");

        // 执行备份
        for (String relativePath : deloyDataMap.keySet()) {
            File exsitFile = new File(deployEntity.getDeployTarget().getAbsolutePath() + relativePath);
            if (!exsitFile.exists()) {
                logger.info("无需备份(新增文件)！： " + relativePath);
                continue;
            }

            try {
                File backupFile = new File(deployEntity.getBackupDir() + File.separator + "files" + relativePath);
                if (!backupFile.getParentFile().exists())
                    backupFile.getParentFile().mkdirs();

                // 只备份文件
                if (exsitFile.isFile()){
                    FileUtils.copyFile(exsitFile, backupFile);
                    if(!backupFile.exists()){
                        throw new IOException("备份文件出错！");
                    }
                    deployEntity.setBackupCount(deployEntity.getBackupCount() + 1);
                    logger.info("备份成功(存在文件)！总数“" + (deployEntity.getBackupCount()) + "” ： " + relativePath);
                }
            } catch (IOException e) {
                e.printStackTrace();
                logger.error("备份文件出错！" + relativePath, e);
                throw new IOException(e);
            }
        }
    }

    /**
     * 执行部署
     */
    @Override
    public void executeDeply(Map<String, File> fileMap) throws IOException {
        logger.info("部署目标路径为：【" + deployEntity.getDeployTarget().getAbsolutePath() + "】");
        for (String relativePath : fileMap.keySet()) {
            File deployFile = fileMap.get(relativePath);
            File targetFile = new File(deployEntity.getDeployTarget().getAbsolutePath() + relativePath);

            // 文件删除，文件夹忽略
            if (targetFile.isFile() && targetFile.exists() && !targetFile.delete()) {
                logger.error("部署前，删除目标失败！");
                throw new IOException("部署前，删除目标失败！");
            }
            try {
                // 创建目录结构
                if(!targetFile.getParentFile().exists())
                    targetFile.getParentFile().mkdirs();

                // 1、部署文件夹
                if(deployFile.isDirectory()){
                    if(!targetFile.exists())
                        targetFile.mkdirs();
                    continue;
                }

                // 2、部署文件
                FileUtils.copyFile(deployFile, targetFile);
                if (!targetFile.exists()) {
                    logger.error("部署后，文件不存在！  没部署上？");
                    throw new IOException("部署后，文件不存在！  没部署上？");
                }

                deployEntity.setSuccessCount(deployEntity.getSuccessCount() + 1);
                logger.info("部署成功！总数“" + deployEntity.getSuccessCount() + "” ： " + relativePath);
            } catch (IOException e) {
                logger.error("部署时发生错误！【" + e.getMessage() + "】", e);
                logger.error("source path : " + deployFile.getCanonicalPath());
                logger.error("target path : " + targetFile.getCanonicalPath());
                throw new IOException(e);
            }
        }
    }

    @Override
    boolean confimContinue() throws IOException, InterruptedException {
        logger.info("\n 请仔细检查输入，以及阅读控制台日志，确认无误后继续！y/n ");

        String inputString = ConsoleHandle.getInputLine().readLine();
        if ("n".equalsIgnoreCase(inputString)) {
            logger.info("程序正在停止...");
            Thread.sleep(2000);
            return false;
        } else if ("y".equalsIgnoreCase(inputString)) {
            logger.info("程序继续执行！");
            return true;
        } else {
            logger.error("输入无效，请重新输入：");
            return confimContinue();
        }
    }
}
